#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <limits> // 用于输入验证
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;	  // Status 是函数返回值类型，其值是函数结果状态代码。
typedef int ElemType; // ElemType 为可定义的数据类型，此设为int类型

struct Book
{
	string id;	  // ISBN
	string name;  // 书名
	double price; // 定价
};
typedef struct DuLNode
{
	Book data;			   // 数据域
	struct DuLNode *prior; // 直接前驱
	struct DuLNode *next;  // 直接后继
} DuLNode, *DuLinkList;

string head_1, head_2, head_3;
int length;

// 清屏函数
void clearScreen()
{
#ifdef _WIN32
	system("cls");
#else
	system("clear");
#endif
}

// 输入验证函数 - 清除输入缓冲区
void clearInputBuffer()
{
	cin.clear();
	cin.ignore(numeric_limits<streamsize>::max(), '\n');
}

// 获取带空格的字符串输入
string getLineInput()
{
	string input;
	getline(cin, input);
	return input;
}

Status InitDuList_L(DuLinkList &L)
{
	// 构造一个空的双向链表L
	L = new DuLNode; // 生成新结点作为头结点，用头指针L指向头结点
	L->next = NULL;	 // 头结点的指针域置空
	L->prior = NULL;
	length = 0;
	return OK;
}

void ClearDuList(DuLinkList &L)
{
	// 销毁双向链表L（保留头结点）
	DuLNode *p = L->next;
	while (p)
	{
		DuLNode *q = p;
		p = p->next;
		delete q;
	}
	L->next = NULL;
	length = 0;
}

DuLNode *GetElemP_DuL(DuLinkList L, int i)
{
	// 在带头结点的双向链表L中查找第i个元素，返回结点的地址
	int j;
	DuLinkList p;
	p = L->next;
	j = 1; // 初始化，p指向第一个结点，j为计数器
	while (j < i && p)
	{ // 顺链域向后扫描，直到p指向第i个元素或p为空
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return NULL; // 第i个元素不存在
	return p;
} // GetElemP_DuL

// 打印单本图书信息
void PrintBook(Book b)
{
	cout << left << setw(15) << b.id << "\t" << left << setw(50) << b.name << "\t" << left << setw(5) << fixed << setprecision(2) << b.price << endl;
}

// 根据ISBN查找图书信息
DuLNode *SearchByISBN(DuLinkList L, string isbn)
{
	DuLNode *p = L->next;
	while (p)
	{
		if (p->data.id == isbn)
		{
			return p;
		}
		p = p->next;
	}
	return NULL;
}

// 根据书名查找图书信息 - 支持模糊查询
DuLNode *SearchByName(DuLinkList L, string name)
{
	DuLNode *p = L->next;
	while (p)
	{
		// 如果书名包含搜索词，则返回该书
		if (p->data.name.find(name) != string::npos)
		{
			return p;
		}
		p = p->next;
	}
	return NULL;
}

// 在表尾添加图书
Status AppendBook(DuLinkList &L, Book e)
{
	// 首先检查ISBN是否已存在
	if (SearchByISBN(L, e.id))
	{
		cout << "错误：ISBN为 " << e.id << " 的图书已存在！" << endl;
		return ERROR;
	}

	DuLNode *s = new DuLNode;
	if (!s)
		return OVERFLOW;
	s->data = e;
	s->next = NULL;

	DuLNode *p = L;
	while (p->next)
	{
		p = p->next;
	}
	// p is now the last node
	p->next = s;
	s->prior = p;
	length++;
	return OK;
}

// 根据ISBN删除图书
Status DeleteByISBN(DuLinkList &L, string isbn)
{
	DuLNode *p = SearchByISBN(L, isbn);
	if (!p)
		return ERROR; // not found

	p->prior->next = p->next;
	if (p->next)
	{ // if not the last node
		p->next->prior = p->prior;
	}
	delete p;
	--length;
	return OK;
}

// 根据ISBN修改图书价格
Status ModifyPriceByISBN(DuLinkList L, string isbn, double new_price)
{
	// 验证价格合法性
	if (new_price <= 0)
	{
		cout << "错误：价格必须大于0！" << endl;
		return ERROR;
	}

	DuLNode *p = SearchByISBN(L, isbn);
	if (p)
	{
		p->data.price = new_price;
		return OK;
	}
	return ERROR;
}

// 按价格排序（冒泡排序），只交换数据域
void SortByPrice(DuLinkList &L)
{
	if (length <= 1)
		return;

	DuLNode *p;
	bool swapped;
	for (int i = 0; i < length - 1; i++)
	{
		swapped = false;
		p = L->next;
		for (int j = 0; j < length - i - 1; j++)
		{
			if (p->data.price > p->next->data.price)
			{
				Book temp = p->data;
				p->data = p->next->data;
				p->next->data = temp;
				swapped = true;
			}
			p = p->next;
		}
		if (!swapped)
			break;
	}
}

// 将图书信息导出到文件
void ExportToFile(DuLinkList L, const string &filename)
{
	ofstream file(filename);
	if (!file)
	{
		cout << "无法打开文件 " << filename << " 进行写入！" << endl;
		return;
	}
	// 注意：这里的头信息是全局变量，在CreateDuList_L中被赋值
	file << head_1 << "\t" << head_2 << "\t" << head_3 << endl;

	DuLNode *p = L->next;
	while (p)
	{
		file << p->data.id << "\t" << p->data.name << "\t" << p->data.price << endl;
		p = p->next;
	}
	file.close();
	cout << "导出成功！共导出 " << length << " 条记录。" << endl;
}

void CreateDuList_L(DuLinkList &L)
{
	// 正位序输入n个元素的值，建立带表头结点的双向链表L，同时建立前驱指针
	ClearDuList(L); // 先清空链表，防止内存泄漏
	DuLinkList r;
	r = L; // 尾指针r指向头结点
	fstream file;
	file.open("book.txt");
	if (!file)
	{
		cout << "未找到相关文件，无法打开！" << endl;
		return; // 使用return而不是exit，更加友好
	}
	file >> head_1 >> head_2 >> head_3;
	while (file.peek() != EOF && file.peek() != '\n')
	{
		DuLNode *p = new DuLNode; // 生成新结点
		file >> p->data.id;
		// 读取可能包含空格的书名
		getline(file >> ws, p->data.name, '\t');
		file >> p->data.price; // 输入元素值

		if (p->data.id.empty())
		{ // 避免读取文件末尾空行
			delete p;
			continue;
		}
		p->next = NULL;
		r->next = p; // 插入到表尾
		p->prior = r;
		r = p; // r指向新的尾结点
		length++;
	}
	file.close();
} // CreateDuList_L

void CreateDuList_L_Keyboard(DuLinkList &L)
{
	ClearDuList(L); // 先清空已有列表
	int n;
	cout << "请输入要创建的图书数量: ";

	// 输入验证
	while (!(cin >> n) || n < 0)
	{
		cout << "输入无效！请输入一个非负整数: ";
		clearInputBuffer();
	}

	if (n == 0)
	{
		cout << "未添加任何图书。" << endl;
		return;
	}

	clearInputBuffer(); // 清除输入缓冲区，准备读取带空格的输入
	cout << "请输入 " << n << " 本图书的信息，每本一行:" << endl;
	cout << "格式: ISBN 书名 价格" << endl;

	for (int i = 0; i < n; ++i)
	{
		Book b;
		cout << "第 " << i + 1 << " 本: ";

		// 读取ISBN
		cin >> b.id;

		// 读取可能包含空格的书名
		clearInputBuffer();
		cout << "请输入书名: ";
		getline(cin, b.name);

		// 读取价格并验证
		cout << "请输入价格: ";
		while (!(cin >> b.price) || b.price <= 0)
		{
			cout << "价格必须是正数！请重新输入: ";
			clearInputBuffer();
		}

		// 尝试添加图书，如果ISBN已存在则提示用户
		if (AppendBook(L, b) != OK)
		{
			cout << "添加失败，请检查ISBN是否重复！" << endl;
			i--; // 重新输入这本书
		}
	}

	// 设置表头
	head_1 = "ISBN";
	head_2 = "书名";
	head_3 = "定价";

	cout << "成功添加 " << n << " 本图书！" << endl;
}

void show_menu()
{
	cout << "\n========================================" << endl;
	cout << "      图书信息管理系统" << endl;
	cout << "========================================" << endl;
	cout << "1. 从文件导入图书信息" << endl;
	cout << "2. 从键盘创建图书信息" << endl;
	cout << "3. 查找图书" << endl;
	cout << "4. 插入新图书" << endl;
	cout << "5. 删除图书" << endl;
	cout << "6. 修改图书价格" << endl;
	cout << "7. 按价格排序" << endl;
	cout << "8. 统计图书数量" << endl;
	cout << "9. 导出到文件" << endl;
	cout << "10. 显示所有图书" << endl;
	cout << "0. 退出" << endl;
	cout << "========================================" << endl;
}

// 显示所有图书的函数
void DisplayAllBooks(DuLinkList L)
{
	if (length == 0)
	{
		cout << "当前没有图书信息可显示。" << endl;
		return;
	}

	cout << "\n当前图书系统信息读出:\n";
	cout << "-----------------------------------------------------------------------------" << endl;
	cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
	cout << "-----------------------------------------------------------------------------" << endl;

	DuLNode *p = L->next;
	while (p)
	{
		PrintBook(p->data);
		p = p->next;
	}
	cout << "-----------------------------------------------------------------------------" << endl;
	cout << "共计 " << length << " 本图书" << endl;
}

int main()
{
	DuLinkList L;
	InitDuList_L(L); // 初始化空链表

	int choice;
	bool list_created = false;

	do
	{
		show_menu();
		cout << "请输入您的选择: ";

		// 输入验证
		while (!(cin >> choice))
		{
			cout << "输入无效！请输入一个数字: ";
			clearInputBuffer();
		}

		switch (choice)
		{
		case 1: // 从文件导入
			CreateDuList_L(L);
			if (length > 0)
			{
				cout << "从 book.txt 导入信息完毕，共导入 " << length << " 条记录。" << endl;
				list_created = true;
			}
			else
			{
				cout << "导入失败或文件为空。" << endl;
			}
			break;
		case 2: // 从键盘创建
			CreateDuList_L_Keyboard(L);
			if (length > 0)
			{
				list_created = true;
			}
			break;
		case 3:
		{ // 查找图书
			if (!list_created)
			{
				cout << "请先创建或导入图书信息！" << endl;
				break;
			}

			int search_choice;
			cout << "请选择查找方式: (1) ISBN (2) 书名: ";
			while (!(cin >> search_choice) || (search_choice != 1 && search_choice != 2))
			{
				cout << "输入无效！请输入1或2: ";
				clearInputBuffer();
			}

			if (search_choice == 1)
			{
				string isbn;
				cout << "请输入ISBN: ";
				cin >> isbn;
				DuLNode *result = SearchByISBN(L, isbn);
				if (result)
				{
					cout << "\n找到图书:" << endl;
					cout << "-----------------------------------------------------------------------------" << endl;
					cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
					cout << "-----------------------------------------------------------------------------" << endl;
					PrintBook(result->data);
					cout << "-----------------------------------------------------------------------------" << endl;
				}
				else
				{
					cout << "未找到ISBN为 " << isbn << " 的图书。" << endl;
				}
			}
			else if (search_choice == 2)
			{
				clearInputBuffer(); // 清除输入缓冲区
				string name;
				cout << "请输入书名(支持模糊查询): ";
				getline(cin, name);

				// 显示所有匹配的图书
				bool found = false;
				DuLNode *p = L->next;

				cout << "\n搜索结果:" << endl;
				cout << "-----------------------------------------------------------------------------" << endl;
				cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
				cout << "-----------------------------------------------------------------------------" << endl;

				while (p)
				{
					if (p->data.name.find(name) != string::npos)
					{
						PrintBook(p->data);
						found = true;
					}
					p = p->next;
				}

				if (!found)
				{
					cout << "未找到包含 \"" << name << "\" 的图书。" << endl;
				}
				cout << "-----------------------------------------------------------------------------" << endl;
			}
			break;
		}
		case 4:
		{ // 插入图书
			if (!list_created)
			{
				cout << "温馨提示: 当前列表为空，新插入的图书将作为第一条记录。" << endl;
				list_created = true; // 插入后列表将不为空
			}

			Book new_book;
			cout << "请输入新图书的ISBN: ";
			cin >> new_book.id;

			// 检查ISBN是否已存在
			if (SearchByISBN(L, new_book.id))
			{
				cout << "错误：ISBN为 " << new_book.id << " 的图书已存在！" << endl;
				break;
			}

			clearInputBuffer(); // 清除输入缓冲区
			cout << "请输入书名: ";
			getline(cin, new_book.name);

			cout << "请输入价格: ";
			while (!(cin >> new_book.price) || new_book.price <= 0)
			{
				cout << "价格必须是正数！请重新输入: ";
				clearInputBuffer();
			}

			if (AppendBook(L, new_book) == OK)
			{
				cout << "图书插入成功！" << endl;
			}
			else
			{
				cout << "图书插入失败。" << endl;
			}
			break;
		}
		case 5:
		{ // 删除图书
			if (!list_created || length == 0)
			{
				cout << "请先创建或导入图书信息！" << endl;
				break;
			}

			string isbn;
			cout << "请输入要删除图书的ISBN: ";
			cin >> isbn;

			// 先查找并显示要删除的图书信息
			DuLNode *p = SearchByISBN(L, isbn);
			if (p)
			{
				cout << "\n要删除的图书信息:" << endl;
				cout << "-----------------------------------------------------------------------------" << endl;
				cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
				cout << "-----------------------------------------------------------------------------" << endl;
				PrintBook(p->data);
				cout << "-----------------------------------------------------------------------------" << endl;

				char confirm;
				cout << "确认删除？(y/n): ";
				cin >> confirm;

				if (confirm == 'y' || confirm == 'Y')
				{
					if (DeleteByISBN(L, isbn) == OK)
					{
						cout << "ISBN为 " << isbn << " 的图书已删除。" << endl;
					}
					else
					{
						cout << "删除失败。" << endl;
					}
				}
				else
				{
					cout << "已取消删除操作。" << endl;
				}
			}
			else
			{
				cout << "未找到ISBN为 " << isbn << " 的图书，删除失败。" << endl;
			}
			break;
		}
		case 6:
		{ // 修改价格
			if (!list_created || length == 0)
			{
				cout << "请先创建或导入图书信息！" << endl;
				break;
			}

			string isbn;
			cout << "请输入要修改图书的ISBN: ";
			cin >> isbn;

			// 先查找并显示要修改的图书信息
			DuLNode *p = SearchByISBN(L, isbn);
			if (p)
			{
				cout << "\n要修改的图书信息:" << endl;
				cout << "-----------------------------------------------------------------------------" << endl;
				cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
				cout << "-----------------------------------------------------------------------------" << endl;
				PrintBook(p->data);
				cout << "-----------------------------------------------------------------------------" << endl;

				double new_price;
				cout << "当前价格: " << p->data.price << endl;
				cout << "请输入新的价格: ";

				while (!(cin >> new_price) || new_price <= 0)
				{
					cout << "价格必须是正数！请重新输入: ";
					clearInputBuffer();
				}

				if (ModifyPriceByISBN(L, isbn, new_price) == OK)
				{
					cout << "价格修改成功！" << endl;
					cout << "\n修改后的图书信息:" << endl;
					cout << "-----------------------------------------------------------------------------" << endl;
					cout << left << setw(15) << head_1 << "\t" << left << setw(50) << head_2 << "\t" << left << setw(5) << head_3 << endl;
					cout << "-----------------------------------------------------------------------------" << endl;
					PrintBook(p->data);
					cout << "-----------------------------------------------------------------------------" << endl;
				}
				else
				{
					cout << "修改失败。" << endl;
				}
			}
			else
			{
				cout << "未找到ISBN为 " << isbn << " 的图书，修改失败。" << endl;
			}
			break;
		}
		case 7: // 排序
		{
			if (!list_created || length == 0)
			{
				cout << "请先创建或导入图书信息！" << endl;
				break;
			}
			SortByPrice(L);
			cout << "图书已按价格升序排序。" << endl;

			// 排序后显示结果
			DisplayAllBooks(L);
			break;
		}
		case 8: // 统计
		{
			cout << "\n当前共有 " << length << " 本图书。" << endl;
			break;
		}
		case 9: // 导出
		{
			if (!list_created || length == 0)
			{
				cout << "列表中没有图书信息可导出。" << endl;
				break;
			}

			string filename;
			cout << "请输入要导出的文件名(默认为book.txt): ";
			clearInputBuffer();
			getline(cin, filename);

			if (filename.empty())
			{
				filename = "book.txt";
			}

			ExportToFile(L, filename);
			break;
		}
		case 10: // 显示所有
		{
			if (!list_created || length == 0)
			{
				cout << "当前没有图书信息可显示。" << endl;
				break;
			}
			DisplayAllBooks(L);
			break;
		}
		case 0:
		{
			cout << "感谢使用，再见！" << endl;
			break;
		}
		default:
		{
			cout << "无效选择，请重新输入。" << endl;
			break;
		}
		}

		// 按任意键继续
		if (choice != 0)
		{
			cout << "\n按回车键继续...";
			clearInputBuffer();
			getchar();
			clearScreen(); // 清屏
		}
	} while (choice != 0);

	ClearDuList(L); // 清理内存
	delete L;		// 释放头结点
	return 0;
}
